package net.zhangdaqian.lightDom;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

public class ElementsCollect implements Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = 6108684105516004997L;
	public List<Element> elements = new ArrayList<Element>();
	private Integer maxLevel = 0;
	private LightDocument lightDocument;

	public LightDocument getDocument() {
		return lightDocument;
	}

	public void setDocument(LightDocument lightDocument) {
		this.lightDocument = lightDocument;
	}

	public Integer getMaxLevel() {
		return maxLevel;
	}

	public ElementsCollect add(Element element) {
		if (element.getLevel() != null && element.getLevel() > maxLevel) {
			maxLevel = element.getLevel();
		}
		elements.add(element);
		return this;
	}

	public ElementsCollect add(ElementsCollect elementsCollect) {
		List<Element> elements = elementsCollect.elements;
		Element element = null;
		for (Iterator<Element> iterator = elements.iterator(); iterator
				.hasNext();) {
			element = iterator.next();
			add(element);
		}
		return this;
	}

	public ElementsCollect getElementsByTagName(String tagName) {
		ElementsCollect elementsCollect = new ElementsCollect();
		Element element = null;
		for (Iterator<Element> iterator = elements.iterator(); iterator
				.hasNext();) {
			element = iterator.next();
			if (element.getTagName().equals(tagName)) {
				elementsCollect.add(element);
			} else {
			}
		}
		return elementsCollect;
	}

	public Element getElementById(String id) {
		Element element = null;
		if (this.getDocument().getFastParse() == false
				&& this.getDocument().getElementsCollect() == this) {
			element = this.getDocument().getElementById(id);
		} else {
			element = getElementByAttr("id", id).sortByInnerId().get(0);
		}
		return element;
	}

	public Element getElementByName(String name) {
		Element element = null;
		if (this.getDocument().getFastParse() == false
				&& this.getDocument().getElementsCollect() == this) {
			element = this.getDocument().getElementByName(name);
		} else {
			element = getElementByAttr("name", name).sortByInnerId().get(0);
		}
		return element;
	}

	public ElementsCollect getElementByAttr(String key, String value) {
		ElementsCollect elementsCollect = new ElementsCollect();
		Element element = null;
		for (Iterator<Element> iterator = elements.iterator(); iterator
				.hasNext();) {
			element = iterator.next();
			if (element.getAttribute(key).equals(value)) {
				elementsCollect.add(element);
			}
		}
		return elementsCollect;
	}

	public Element getElementByInnerId(Integer id) {
		// TODO Auto-generated method stub
		Element element = null;
		for (Iterator<Element> iterator = elements.iterator(); iterator
				.hasNext();) {
			element = iterator.next();
			if (element.getInnerId().equals(id)) {
				break;
			} else {
				element = null;
			}
		}
		return element;
	}

	public String toStringContent() {
		StringBuffer content = new StringBuffer();
		for (Iterator<Element> iterator = elements.iterator(); iterator
				.hasNext();) {
			Element element = iterator.next();
			content.append(element.getContent());
			content.append("\n");
			// System.out.println(1);
		}
		return content.toString();
	}

	public Integer length() {
		return this.elements.size();
	}

	public ElementsCollect getElementsByLevel(Integer level) {
		// TODO Auto-generated method stub
		ElementsCollect elementsCollect = new ElementsCollect();
		for (Iterator<Element> iterator = elements.iterator(); iterator
				.hasNext();) {
			Element element = iterator.next();
			if (element.getLevel() == level) {
				elementsCollect.add(element);
			}
		}
		return elementsCollect;
	}

	public class ElementsCollectComparatorByInnerId implements
			Comparator<Element> {
		@Override
		public int compare(Element element1, Element element2) {
			// TODO Auto-generated method stub
			if (null == element1.getInnerId() || null == element2.getInnerId()) {
				return -9999999;
			}
			return element1.getInnerId().compareTo(element2.getInnerId());
		}

	}

	public ElementsCollect sortByInnerId() {
		Collections.sort(elements, new ElementsCollectComparatorByInnerId());
		return this;
	}

	public Element get(int index) {
		sortByInnerId();
		if (index < elements.size()) {
			return elements.get(index);
		} else {
			return null;
		}
	}

	public Integer indexOf(Element element) {
		LinkedList<String> attrs = new LinkedList<String>();
		attrs.addFirst("level");
		attrs.addFirst("tagName");
		if (element.getId() != null)
			attrs.addFirst("id");
		if (element.getName() != null)
			attrs.add("name");
		return indexOf(element, attrs, 0.9);
	}

	private class TagSort implements Comparator<String> {
		@Override
		public int compare(String arg0, String arg1) {
			if (arg0.equals("id")) {
				return 1;
			} else if (arg0.equals("name")) {
				return 2;
			} else if (arg0.equals("level")) {
				return 3;
			} else if (arg0.equals("tagName")) {
				return 4;
			}
			return 999;
		}
	}

	public Integer indexOf(Element element, List<String> attrs, double tolerance) {
		Collections.sort(attrs, new TagSort());
		ElementsCollect resultCollect = new ElementsCollect();
		for (Iterator<String> iterator = attrs.iterator(); iterator.hasNext();) {
			String attr = iterator.next();
			if (attr.equals("id")) {
				resultCollect = resultCollect.indexOfAdd(resultCollect, this
						.getElementById(element.getId()));
			} else if (attr.equals("name")) {
				resultCollect = resultCollect.indexOfAdd(resultCollect, this
						.getElementByName(element.getName()));
			} else if (attr.equals("level")) {
				resultCollect = resultCollect.indexOfAdd(resultCollect, this
						.getElementsByLevel(element.getLevel()));
			} else if (attr.equals("tagName")) {
				resultCollect = resultCollect.indexOfAdd(resultCollect,
						resultCollect.getElementsByLevel(element.getLevel()));
			} else {
				resultCollect = resultCollect.indexOfAdd(resultCollect, this
						.getElementByAttr(attr, element.getAttribute(attr)));
			}
		}
		int maxInnerId = -1;
		if (attrs.size() >= 2) {
			int maxCount = 0;
			for (Iterator<Element> iterator = resultCollect.elements.iterator(); iterator
					.hasNext();) {
				Element _element = iterator.next();
				if (_element.i_freeToUse > maxCount) {
					maxCount = _element.i_freeToUse;
					maxInnerId = _element.getInnerId();
				}
			}
			if ((maxCount / attrs.size()) < tolerance) {
				maxInnerId = -1;
			}
		} else {
		}
		return maxInnerId;
	}

	// Please do not care about this function,this is an ugly
	// implementation,some day I will rewrite this part.Any way this fuction is
	// another implement of this.add(Element),but his one does a innerId
	// check,from the angle of efficiency,I didn't do this check in add,which is
	// also not necessary.
	private ElementsCollect indexOfAdd(ElementsCollect elementsCollect,
			Element element) {
		element.i_freeToUse++;
		if (getElementByInnerId(element.getInnerId()) == null) {
			elementsCollect.elements.add(element);
		}
		return elementsCollect;
	}

	private ElementsCollect indexOfAdd(ElementsCollect source,
			ElementsCollect add) {
		List<Element> elements = add.elements;
		Element element = null;
		for (Iterator<Element> iterator = elements.iterator(); iterator
				.hasNext();) {
			element = iterator.next();
			indexOfAdd(source, element);
		}
		return this;
	}

	public String toString() {
		StringBuffer result = new StringBuffer();
		for (Iterator<Element> iterator = elements.iterator(); iterator
				.hasNext();) {
			Element element = iterator.next();
			result.append(element.toString());
		}
		return result.toString();
	}
}
